#pragma once

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <ctime>


// 日志是有日志等级的

// 根据文件级别，分文件打印，就不分了
// const std::string filename = "tcpserver.log.debug";
// const std::string filename = "tcpserver.log.info";
// const std::string filename = "tcpserver.log.warning";
// const std::string filename = "tcpserver.log.error";
// const std::string filename = "tcpserver.log.fatal";
// const std::string filename = "tcpserver.log.uknown";
const std::string filename = "log/tcpserver.log";

// #define DEBUG 0
// #define INFO 1
// #define WARNING 2
// #define ERROR 3
// #define FATAL 4
// #define UNKNOW 5
enum
{
    Debug = 0,
    Info,
    Warning, // 告警错误
    Error,
    Fatal, // 致命错误
    Uknown,
};

static std::string toLevelString(int level)
{
    switch (level)
    {
    case Debug:
        return "Debug";
    case Info:
        return "Info";
    case Warning:
        return "Warning";
    case Error:
        return "Error";
    case Fatal:
        return "Fatal";
    default:
        return "Uknown";
    }
}

static std::string getTime() // 获取时间
{
    // int tm_sec;                        /* Seconds.	[0-60] (1 leap second) */
    // int tm_min;                        /* Minutes.	[0-59] */
    // int tm_hour;                       /* Hours.	[0-23] */
    // int tm_mday;                       /* Day.		[1-31] */
    // int tm_mon;                        /* Month.	[0-11] */
    // int tm_year;                       /* Year	- 1900.  */
    // int tm_wday;                       /* Day of week.	[0-6] */
    // int tm_yday;                       /* Days in year.[0-365]	*/
    // int tm_isdst;                      /* DST.		[-1/0/1]*/
    time_t curr = time(nullptr);
    struct tm *tmp = localtime(&curr); // 把time_t类型转化成struct结构
    char buffer[128];
    snprintf(buffer, sizeof(buffer), "%d-%d-%d %d:%d:%d", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
             tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
    return buffer;
}

//...表示可变参数
// 日志是有格式的：日志等级，时间，哪个进程pid，消息体
// logMessage（DEBUG,"hello: %d %s",12,s.c_str());//DEBUG hello：12，world
// 传进来的format参数可能是双引号括起来的字符串常量，一定要加const
void logMessage(int level, const char *format, ...) // 消息体是format，是右半部分，是可变部分
{
    char logLeft[1024];
    std::string file;
    std::string level_string = toLevelString(level);
    std::string curr_time = getTime();

    snprintf(logLeft, sizeof(logLeft), "[%s] [%s] [%d] ", level_string.c_str(), curr_time.c_str(), getpid());

    char logRight[1024];
    va_list p;
    va_start(p, format);
    vsnprintf(logRight, sizeof(logRight), format, p); // 写完的数据，放到logRight这个缓冲区里,可变部分是p
    va_end(p);

    // 打印
    // printf("%s%s\n", logLeft, logRight);

    // 保存到文件中
    FILE *fp = fopen(filename.c_str(), "a");
    if (fp == nullptr)
        return;
    fprintf(fp, "%s%s\n", logLeft, logRight);
    fflush(fp); // 可写，可不写
    fclose(fp);

    // 解释，预备
    //  va_list p;              // char*
    //  int a = va_arg(p, int); // 根据类型提取参数
    //  va_start(p, format);    // 指针p指向可变参数部分的起始地址
    //  va_end(p);              // p=NULL,不用了，直接置为NULL
}